﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Algobox.JuicyLib.MarketData;
using Algobox.JuicyLib.SQL.LiquidView;

namespace Algobox.JuicyLib.Apps.StrikeImporter
{
    /// <summary>
    /// importer class to process csv data + insert into db
    /// </summary>
    public class StrikeImporter
    {
        /// <summary>
        /// dsn connection string 
        /// </summary>
        private string connectionString = null;

        public string ConnectionString
        {
            get { return connectionString; }
            set { connectionString = value; }
        }

        /// <summary>
        /// Set current sate of task for current file to be processed
        /// </summary>
        private ImporterTasks importerMode = ImporterTasks.None;

        private ImporterTasks ImporterMode
        {
            get { return importerMode; }
         }
        
        private enum ImporterTasks
        { 
            None,                       //0
            StockTrades,
            StockOrders
        }

        private enum AssetTypes
        {
            Stock   = 'S',
            Cash    = 'C',
            Future  = 'F',
            FX      = 'X',
            Option  = 'O'
        }


        private enum FieldsStockTradeFile
        {
            HostName,                   //0
            HostType,
            HostOrderId,
            HostTradeId,
            ExchangeIdentifier,
            ExchangeOrderId,
            ExchangeTradeId,
            AccountId,
            Currency,
            ISIN,
            Sedol,
            Symbol,
            Quantity,
            Price,
            TradeTime,
            CounterpartyCode,
            MarketParticipant,
            AggressorFlag,
            ManualFlag,
            InternalFlag,
            MarketSegment,
            BrokerCode
        }


        private enum FieldsStockOrdersFile
        {
            HostName,                   //0
            HostType,
            Action,
            OrderType,
            HostOrderId,
            ExchangeIdentifier,
            ExchangeOrderId,
            AccountId,
            Currency,
            ISIN,
            Sedol,
            Symbol,
            OrderTime,
            ValidityType,
            MarketSegment,
            BrokerCode
        }

        /// <summary>
        /// MS generated sql class to access trade/order input sps
        /// </summary>
        Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext sqlImporter = null;

        public StrikeImporter(string connectionStringIn)
        {
            connectionString = connectionStringIn;

            if (connectionString != string.Empty)
            {
                sqlImporter = new Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext(connectionStringIn);
            }
            else
            {
                sqlImporter = new Algobox.JuicyLib.SQL.LiquidView.LiquidViewLinqDataContext();
            }
        }


        public void Log(string message)
        {
            sqlImporter.ExceptionHandlerThrow("StrikeImporter", message, null);
        }

        

        /// <summary>
        /// Search string for Orders in imported file name
        /// </summary>
        private const string ORDERS = "ORDERS";
        /// <summary>
        /// Search string for Trades in imported file name
        /// </summary>
        private const string TRADES = "TRADES";


        /// <summary>
        /// use filename to determine if we should process by setting importtask member variable
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public bool FilterFileName(string fileName)
        {
            if (fileName.IndexOf(ORDERS) > 0)
            {
                importerMode = ImporterTasks.StockOrders;
                return true;
            }
            else if (fileName.IndexOf(TRADES) > 0)
            {
                importerMode = ImporterTasks.StockTrades;
                return true;
            }
            else
            {
                Console.WriteLine("File name filtered on FTP site: " + fileName);
                Log("File name filtered on FTP site: " + fileName);
            }

            return false;
        }


        private const char DELIMITER = ',';

        /// <summary>
        /// process the file
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public bool ProcessStream(StreamReader reader)
        {
            string fileLine;
            string[] arrayData;
            bool retOK = false;

            try
            {
                while (reader.BaseStream.CanRead && !reader.EndOfStream)
                {
                    fileLine = reader.ReadLine();

                    arrayData = fileLine.Split(DELIMITER);

                    // check that this line contains some data
                    if (arrayData.Length > 1)
                    {
                        System.Console.WriteLine(fileLine);

                        switch (importerMode)
                        {
                            case ImporterTasks.StockTrades:
                                retOK = ProcessStockTrade(arrayData);
                                if (!retOK)
                                    Log("ProcessStockTrade Failed: " + fileLine);
                                break;
                            case ImporterTasks.StockOrders:
                                retOK = ProcessStockOrder(arrayData);
                                if (!retOK)
                                    Log("ProcessStockOrder Failed: " + fileLine);
                                break;
                            default:
                                retOK = false;
                                Log("New security type unhandled: " + ((ImporterTasks)importerMode).ToString());
                                Log("Unhandled line: " + fileLine);
                                break;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log("Caught Exception in StrikeImporter.ProcessStream(), message was: " + e.Message);
            }

            return true;
        }
              
        /// <summary>
        /// process the trade
        /// </summary>
        /// <param name="data"></param>
        private bool ProcessStockTrade(string[] data)
        {
            string currency = string.Empty;
            decimal price = 0;

            try
            {
                bool isGBXorGBp = false;

                currency = MarketDataHelper.ConvertGBXGBpToGBP(data[(int)FieldsStockTradeFile.Currency], out isGBXorGBp);

                if (isGBXorGBp)
                {
                    price = decimal.Parse(data[(int)FieldsStockTradeFile.Price]) / 100;
                }
                else
                    price = decimal.Parse(data[(int)FieldsStockTradeFile.Price]);

                string marketSegment = null;
                if ((int)FieldsStockTradeFile.MarketSegment < data.Length)
                    marketSegment = data[(int)FieldsStockTradeFile.MarketSegment];
 
                string brokerCode = null;
                if ((int)FieldsStockTradeFile.BrokerCode < data.Length)
                    brokerCode = data[(int)FieldsStockTradeFile.BrokerCode];

                    sqlImporter.ImportTrade(
                    (char)AssetTypes.Stock,
                    data[(int)FieldsStockTradeFile.HostName],
                    data[(int)FieldsStockTradeFile.HostType],
                    data[(int)FieldsStockTradeFile.HostOrderId],
                    data[(int)FieldsStockTradeFile.HostTradeId],
                    data[(int)FieldsStockTradeFile.ExchangeIdentifier],
                    data[(int)FieldsStockTradeFile.ExchangeOrderId],
                    data[(int)FieldsStockTradeFile.ExchangeTradeId],
                    data[(int)FieldsStockTradeFile.AccountId],
                    currency,
                    data[(int)FieldsStockTradeFile.ISIN],
                    data[(int)FieldsStockTradeFile.Sedol],
                    null,
                    data[(int)FieldsStockTradeFile.Symbol],
                    null,
                    null,
                    null,
                    long.Parse(data[(int)FieldsStockTradeFile.Quantity]),
                    price,
                    DateTime.Parse(data[(int)FieldsStockTradeFile.TradeTime]),
                    data[(int)FieldsStockTradeFile.CounterpartyCode],
                    data[(int)FieldsStockTradeFile.MarketParticipant],
                    int.Parse(data[(int)FieldsStockTradeFile.AggressorFlag]) == 1 ? true : false,
                    int.Parse(data[(int)FieldsStockTradeFile.ManualFlag]) == 1 ? true : false,
                    int.Parse(data[(int)FieldsStockTradeFile.InternalFlag]) == 1 ? true : false,
                    marketSegment,
                    brokerCode,
                    null,
                    null,
                    null);

            }
            catch (Exception e)
            {
                Log("ProcessStockTrade Failed: " + e.ToString());
                return false;
            }

            return true;
        }



        /// <summary>
        /// process the order
        /// </summary>
        /// <param name="data"></param>
        private bool ProcessStockOrder(string[] data)
        {
            string currency = string.Empty;

            bool isGBXorGBp = false;

            try
            {       
                currency = MarketDataHelper.ConvertGBXGBpToGBP(data[(int)FieldsStockTradeFile.Currency],out isGBXorGBp);

                string validityType = null;
                if ((int)FieldsStockOrdersFile.ValidityType < data.Length)
                    validityType = data[(int)FieldsStockOrdersFile.ValidityType];

                string marketSegment = null;
                if ((int)FieldsStockOrdersFile.MarketSegment < data.Length)
                    marketSegment = data[(int)FieldsStockOrdersFile.MarketSegment];

                string brokerCode = null;
                if ((int)FieldsStockOrdersFile.BrokerCode < data.Length)
                    brokerCode = data[(int)FieldsStockOrdersFile.BrokerCode];

                sqlImporter.ImportOrder(
                    (char)AssetTypes.Stock,
                    data[(int)FieldsStockOrdersFile.HostName],
                    data[(int)FieldsStockOrdersFile.HostType],
                    data[(int)FieldsStockOrdersFile.Action],
                    data[(int)FieldsStockOrdersFile.OrderType],
                    data[(int)FieldsStockOrdersFile.HostOrderId],
                    data[(int)FieldsStockOrdersFile.ExchangeIdentifier],
                    data[(int)FieldsStockOrdersFile.ExchangeOrderId],
                    data[(int)FieldsStockOrdersFile.AccountId],
                    currency,
                    data[(int)FieldsStockOrdersFile.ISIN],
                    data[(int)FieldsStockOrdersFile.Sedol],
                    data[(int)FieldsStockOrdersFile.Symbol],
                    DateTime.Parse(data[(int)FieldsStockOrdersFile.OrderTime]),
                    null, null,
                    validityType,
                    marketSegment,
                    brokerCode);
            }
            catch (Exception e)
            {
                Log("ProcessStockTrade Failed: " + e.ToString());
                return false;
            }

            return true;
        }

    }
}
